package server.price;

import java.sql.ResultSet;
import java.sql.SQLException;
import server.Logger;
import server.conn.ConnectionThread;
import server.db.DBObject;
import server.db.DataBase;
import server.order.Order;

public class Price extends DBObject {
	public static final String TABLE = "prices";
	public static final String CUR_1 = "cur1";
	public static final String CUR_2 = "cur2";
	public static final String BUY = "buy";
	public static final String SELL = "sell";
	public static final String TIME = "time";
	
	public static final int MAX_HISTORY = 50;
	
	private String cur1;
	private String cur2;
	private float buy;
	private float sell;
	private long time;
	
	/**
	 * Create a new price
	 * @param cur1	Base currency
	 * @param cur2	Quote currency
	 */
	public Price(String cur1, String cur2) {
		super();
		this.cur1 = cur1;
		this.cur2 = cur2;
		buy = 0;
		sell = 0;
		time = 0;
		getLatestQuote();
		Logger.getInstance().addLog("Price "+cur1+cur2+" has been initialized. Buy = "+buy+", Sell = "+sell, 4);
	}
	
	/**
	 * Create a new price and get data from a ResultSet
	 * @param cur1	Base currency
	 * @param cur2	Quote currency
	 * @param rs	ResultSet to get data from
	 * @throws SQLException
	 */
	private Price(String cur1, String cur2, ResultSet rs) throws SQLException {
		super();
		this.cur1 = cur1;
		this.cur2 = cur2;
		buy = rs.getFloat(BUY);
		sell = rs.getFloat(SELL);
		time = rs.getLong(TIME);
	}
	
	/**
	 * Update price from database
	 */
	private final void getLatestQuote() {
		ResultSet rs = getHistory(1);
		
		try {
			rs.first();
			buy = rs.getFloat(BUY);
			sell = rs.getFloat(SELL);
			time = rs.getLong(TIME);
		} catch (SQLException e) {
			Logger.getInstance().addError("Could not get latest quote for "+cur1+"/"+cur2, 2);
		}
	}
	
	/**
	 * Return a ResultSet containing price history
	 * @param limit		Max records to return in ResultSet
	 * @return			ResultSet containing price history
	 */
	public ResultSet getHistory(int limit) {
		limit = (limit > MAX_HISTORY) ? MAX_HISTORY : limit;
		
		String query = "SELECT "+BUY+","+SELL+","+TIME+" FROM "+TABLE+" WHERE";
		query += "("+CUR_1+"=\""+cur1+"\" AND "+CUR_2+"=\""+cur2+"\") ORDER BY "+TIME+" DESC LIMIT "+limit;
		try {
			return doQuery(query);
		} catch (SQLException e) {
			Logger.getInstance().addError("Could not get price history for "+cur1+"/"+cur2, 2);
			return null;
		}
	}
	
	/**
	 * Update the prices buy and sell values
	 * @param buy	New buy price
	 * @param sell	New sell price
	 * @return		True if update was successful
	 */
	public boolean updatePrice(float buy, float sell) {
		return updatePrice(buy, sell, true);
	}
	
	/**
	 * @see Price#updatePrice(float, float)
	 * @param buy				New buy price
	 * @param sell				New sell price
	 * @param updateInverse		True to update inverse
	 * @return					True if update was successful
	 */
	public boolean updatePrice(float buy, float sell, boolean updateInverse) {	
		boolean result = true;
		long curTime = (System.currentTimeMillis()/1000);
		
		String query = "INSERT INTO "+TABLE+" ("+CUR_1+","+CUR_2+","+BUY+","+SELL+","+TIME+") ";
		query += "VALUES (\""+cur1+"\",\""+cur2+"\","+buy+","+sell+","+curTime+")";
		
		try {
			doUpdate(query);
			this.buy = buy;
			this.sell = sell;
			this.time = curTime;
		} catch (SQLException e) {
			Logger.getInstance().addSQLQueryError("Could not update price "+cur1+"/"+cur2, query, 2);
			return false;
		}
		
		if (updateInverse)
			result = updateInverse();
		
		return result;
	}
	
	/**
	 * Update the prices inverse
	 * @return	True if update was successful
	 */
	private boolean updateInverse() {
		boolean result = true;
		
		float newBuy = 1/sell;
		float newSell = 1/buy;
		
		result = PriceController.getInstance().getPrice(cur2, cur1).updatePrice(newBuy, newSell, false);
		
		return result;
	}
	
	public float getBuy() { return buy; }
	public float getSell() { return sell; }
	public long getTime() { return time; }
	public String getCur1() { return cur1; }
	public String getCur2() { return cur2; }
	
	/**
	 * Return a string representation for sending over a scoket
	 */
	public String toString() {
		return cur1+ConnectionThread.SPLIT+cur2+ConnectionThread.SPLIT+buy+ConnectionThread.SPLIT+sell+ConnectionThread.SPLIT+time;
	}
	
	/**
	 * Return a shortened version of {@link Order#toString()}
	 * @param bType
	 * @return	Shortened version of toString
	 */
	public String toShortString(int bType) {
		if (bType == Order.SELL)
			return sell+ConnectionThread.SPLIT+time;
		else
			return buy+ConnectionThread.SPLIT+time;
	}
	
	/**
	 * Return price history as an array of strings
	 * @param limit		Max records to return
	 * @param bType		Buy or sell
	 * @return			String array of history
	 * @throws SQLException
	 */
	public String[] historyToString(int limit, int bType) throws SQLException {
		ResultSet rs = getHistory(limit);
		
		String[] retStr = new String[DataBase.getRows(rs)];
		
		int aCounter = 0;
		do {
			retStr[aCounter++] = new Price(cur1, cur2, rs).toShortString(bType);
		} while (rs.next());
		
		return retStr;
	}
	
}
